/*
 * 文件名： CiticExPayManage.java
 * 
 * 工程名称: bis-manager
 *
 * Gopay
 *
 * 创建日期： 2016年6月17日
 *
 * Copyright(C) 2016, by www.gopay.com.cn Inc.All rights reserved.
 *
 * 原始作者: 宣广海
 *
 */
package com.gopay.bis.manager.bank.expay;

import java.util.Date;
import java.util.Map;
import java.util.UUID;

import javax.annotation.Resource;

import com.gopay.bis.common.util.BankLogUtils;
import com.gopay.bis.common.util.TransUtils;
import com.gopay.bis.dao.bankorder.BankContractInfoDAO;
import com.gopay.common.cipher.utils.LoggerMaskUtils;
import com.gopay.common.constants.bank.BankContractConstants;
import com.gopay.common.constants.bank.BisBankBusinessProd;
import com.gopay.common.cps.dao.order.CpsGeneralReceiptOrderQueryDAO;
import com.gopay.common.cps.manager.order.CpsGeneralMainOrderQueryManager;
import com.gopay.common.domain.bank.ExPayBaseMessage;
import com.gopay.common.domain.bank.citic.expay.CiticExpay;
import com.gopay.common.domain.bank.citic.expay.CiticExpayMessage;
import com.gopay.common.domain.bank.citic.expay.CiticExpayReqMessage;
import com.gopay.common.domain.bank.citic.expay.CiticExpayResMessage;
import com.gopay.common.domain.bank.citic.expay.certification.CiticExpayCerReqMessage;
import com.gopay.common.domain.bank.citic.expay.pay.CiticExpayPayReqMessage;
import com.gopay.common.domain.bank.citic.expay.query.CiticExpayQueryReqMessage;
import com.gopay.common.domain.bank.citic.expay.refund.CiticExpayRefundReqMessage;
import com.gopay.common.domain.bank.citic.expay.sign.CiticExpaySignReqMessage;
import com.gopay.common.domain.bis.BisBankContractInfo;
import com.gopay.common.domain.cps.CpsGenMainOrder;
import com.gopay.common.domain.cps.CpsGenReceiptOrder;
import com.gopay.common.exception.GopayException;
import com.gopay.common.util.DateUtils;
import com.gopay.remote.bank.businesses.ExPayService;
import com.thoughtworks.xstream.XStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 中信银行快捷支付报文处理类
 *
 * @author 宣广海
 *
 * @version
 *
 * @since 2016年6月17日
 */
public class CiticExPayManage {

    /**
     * 注入对象
     */
    @Resource(name = "citicExPayServiceClient")
    private ExPayService citicExPayServiceClient;

    @Resource(name = "citicConfig")
    private Map<String, String> citicConfig;

    @Resource(name = "bankContractInfoDAO")
    private BankContractInfoDAO bankContractInfoDAO;
    
    @Resource(name = "cpsGeneralMainOrderQueryManager")
    private CpsGeneralMainOrderQueryManager mainOrderQuery;
    
    @Resource(name = "cpsGeneralReceiptOrderQueryDAO")
    protected CpsGeneralReceiptOrderQueryDAO recvOrderDAO;
    
    private static final String DATE_FORMAT = "yyyyMMdd HH:mm:ss"; //时间格式

    private final static Logger logger = LoggerFactory.getLogger(CiticExPayManage.class);

    /**
     * 
     * 功能描述：中信银行快捷支付支付请求
     *
     * @param citicExpay
     * @return
     * @throws GopayException
     * 
     * @author 宣广海
     *
     * @since 2016年6月20日
     *
     * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
     */
    public Object payment(CiticExpay citicExpay) throws GopayException {
        CiticExpayReqMessage reqMessage = this.buildExpayPayReqMessage(citicExpay);
        String plainMessage = toXML(reqMessage);
        logger.info(citicExpay.getOutStlmCd() + " exPay payment plainMessage: " + LoggerMaskUtils.maskString(plainMessage));
        BankLogUtils.printExPayPaymentSendLog(citicExpay);
        citicExpay.setPlainMessage(plainMessage);
        CiticExpayResMessage resMessage = (CiticExpayResMessage) citicExPayServiceClient.payment(citicExpay);
        resMessage.setOutStlmCd(citicExpay.getOutStlmCd());
        BankLogUtils.printExPayPaymentReturnLog(resMessage, null);
        return resMessage;
    }
    
    /** 
     * 功能描述：中信银行快捷支付退款请求
     * @param citicExpay
     * @return
     * @throws GopayException 
     * @author w_jiqing 
     */
    public Object refund(CiticExpay citicExpay) throws GopayException{
        CiticExpayReqMessage reqMessage = this.buildExpayRefundMessage(citicExpay);
        String plainMessage = toXML(reqMessage);
        citicExpay.setPlainMessage(plainMessage);
        BankLogUtils.printExpayManagerRefundSendLog(citicExpay);
        CiticExpayResMessage resMessage = (CiticExpayResMessage) citicExPayServiceClient.refund(citicExpay);
        resMessage.setOutStlmCd(citicExpay.getOutStlmCd());
        BankLogUtils.printExpayManagerRefundReturnLog(resMessage);
        return resMessage;
    }

    /**
     * 
     * 功能描述：中信银行快捷支付单笔订单查询
     *
     * @param citicExpay
     * @return
     * @throws GopayException
     * 
     * @author 宣广海
     *
     * @since 2016年6月27日
     *
     * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
     */
    public Object queryOrder(CiticExpay citicExpay) throws GopayException {

        CiticExpayReqMessage reqMessage = this.buildExpayQueryReqMessage(citicExpay);
        String plainMessage = toXML(reqMessage);
        citicExpay.setPlainMessage(plainMessage);
        BankLogUtils.printExPayManagerQuerySendLog(citicExpay);
        CiticExpayResMessage resMessage = (CiticExpayResMessage) citicExPayServiceClient.queryOrder(citicExpay);
        resMessage.setOutStlmCd(citicExpay.getOutStlmCd());
        BankLogUtils.printExPayManagerQueryReturnLog(resMessage);
        return resMessage;

    }

    /**
     * 
     * 功能描述：中信银行鉴权
     *
     * @param citicExpay
     * @return
     * @throws GopayException
     * 
     * @author 宣广海
     *
     * @since 2016年6月29日
     *
     * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
     */
    public Object certification(CiticExpay citicExpay) throws GopayException {

        CiticExpayReqMessage reqMessage = this.buildExpayCerReqMessage(citicExpay);
        String plainMessage = toXML(reqMessage);
        citicExpay.setPlainMessage(plainMessage);
        BankLogUtils.printExPayManagerCertificationSendLog(citicExpay);
        CiticExpayResMessage resMessage = (CiticExpayResMessage) citicExPayServiceClient.certification(citicExpay);
        resMessage.setOutStlmCd(citicExpay.getOutStlmCd());
        BankLogUtils.printExPayManagerCertificationReturnLog(resMessage);
        return resMessage;

    }

    /**
     * 
     * 功能描述：中信银行快捷支付签约
     *
     * @param citicExpay
     * @return
     * @throws GopayException
     * 
     * @author 宣广海
     *
     * @since 2016年7月1日
     *
     * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
     */
    public Object sign(CiticExpay citicExpay) throws GopayException {

        CiticExpayReqMessage reqMessage = this.buildExpaySignReqMessage(citicExpay);
        String plainMessage = toXML(reqMessage);
        logger.info(citicExpay.getOutStlmCd() + " exPay manager sign plainMessage: " + LoggerMaskUtils.maskString(plainMessage));
        BankLogUtils.printExPayManagerSignSendLog(citicExpay);
        citicExpay.setPlainMessage(plainMessage);
        CiticExpayResMessage resMessage = (CiticExpayResMessage) citicExPayServiceClient.sign(citicExpay);
        resMessage.setOutStlmCd(citicExpay.getBank());
        BankLogUtils.printExPayManagerSignReturnLog(resMessage);
        return resMessage;

    }

    /**
     * 
     * 功能描述：构建支付请求报文
     *
     * @param citicExpay
     * @return
     * 
     * @author 宣广海
     *
     * @since 2016年6月20日
     *
     * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
     */
    public CiticExpayReqMessage buildExpayPayReqMessage(CiticExpay citicExpay) {

        CiticExpayReqMessage reqMessage = new CiticExpayReqMessage();
        CiticExpayMessage expayMessage = new CiticExpayMessage();
        CiticExpayPayReqMessage payReqMessage = new CiticExpayPayReqMessage();
        CpsGenMainOrder mainOrder = mainOrderQuery.get(citicExpay.getOrderId());
        // 金额，以分为单位
        String amount = TransUtils.amountConvert2Fen(citicExpay.getAmount().toString());
        payReqMessage.setId("CPReq");
        //报文标示
        payReqMessage.setStdprocode("CPReq");
        payReqMessage.setAmount(amount);
        // 机构标识
        payReqMessage.setInstId(citicExpay.getMerID());
        // 数字证书标识
        payReqMessage.setCertId(citicConfig.get("CITIC.EXPAY.CERTID"));
        payReqMessage.setCurrency(citicConfig.get("CITIC.EXPAY.CURRENCY"));
        payReqMessage.setVersion(citicConfig.get("CITIC.EXPAY.VERSION"));
        //交易类型
        payReqMessage.setTranType(citicConfig.get("CITIC.EXPAY.TRANTYPE"));
        payReqMessage.setPayerName(citicExpay.getCardHolder());
        payReqMessage.setPayerAcct(citicExpay.getCardNo());
        if ((BisBankBusinessProd._15.value).equals(citicExpay.getBankBusProd().value)) {
            payReqMessage.setPayerAcTp("D");// 借机卡
        }
        //付款方所属机构标识
        payReqMessage.setPayerIstFlag(citicConfig.get("CITIC.EXPAY.PAYERISTFLAG"));
        //收款方名称
        payReqMessage.setPayeeName(citicConfig.get("CITIC.EXPAY.PAYEENAME"));
        //收款方账号
        payReqMessage.setPayeeAcct(citicConfig.get("CITIC.EXPAY.PAYEEACCT"));
        // 支付订单号
        payReqMessage.setSerialNo(citicExpay.getBankOrderId());
        // 签约协议号
        payReqMessage.setSignNo(citicExpay.getAgrmtNo());
        // 交易日期和时间 YYYYMMDD HH:MM:SS
        payReqMessage.setDate(DateUtils.format(mainOrder.getCreatedTs(), DATE_FORMAT));
        String messageId = UUID.randomUUID().toString();
        expayMessage.setId(messageId.replaceAll("-", ""));
        expayMessage.setSysname(citicConfig.get("CITIC.EXPAY.SYSNAME"));
        expayMessage.setPayReqMessage(payReqMessage);
        reqMessage.setExpayMessage(expayMessage);
        return reqMessage;

    }
    
    /** 
     * 功能描述：构建退款请求报文
     * @param citicExpay
     * @return 
     * @author w_jiqing 
     */
    public CiticExpayReqMessage buildExpayRefundMessage(CiticExpay citicExpay){
        CiticExpayReqMessage reqMessage = new CiticExpayReqMessage();
        CiticExpayMessage expayMessage = new CiticExpayMessage();
        CiticExpayRefundReqMessage refundReqMessage = new CiticExpayRefundReqMessage();
        CpsGenMainOrder refundMainOrder = mainOrderQuery.get(citicExpay.getOrderId());
        CpsGenMainOrder payMainOrder = mainOrderQuery.get(citicExpay.getTkOriOrderId());
        CpsGenReceiptOrder orgRecvOrder = recvOrderDAO.find(CpsGenReceiptOrder.class, citicExpay.getTkOriOrderId());
        citicExpay.setCardNo(orgRecvOrder.getEpBankCardNo());
        refundReqMessage.setId("CRReq");
        refundReqMessage.setVersion(citicConfig.get("CITIC.EXPAY.VERSION"));
        refundReqMessage.setInstId(citicExpay.getMerID());
        refundReqMessage.setCertId(citicConfig.get("CITIC.EXPAY.CERTID"));
        refundReqMessage.setStdprocode("CRReq");
        //退款流水号
        refundReqMessage.setSerialNo(citicExpay.getBankOrderId());
        //原订单号
        refundReqMessage.setOrgSerialNo(citicExpay.getTkOriBankOrderId());
        //原订单日期
        refundReqMessage.setOrgDate(DateUtils.format(payMainOrder.getCreatedTs(), DATE_FORMAT));
        //交易日期和时间
        refundReqMessage.setDate(DateUtils.format(refundMainOrder.getCreatedTs(), DATE_FORMAT));
        //协议号
        BisBankContractInfo bbci = getSignNo(citicExpay);
        refundReqMessage.setSignNo(bbci.getContractNumber());
        // 金额，以分为单位
        String amount = TransUtils.amountConvert2Fen(citicExpay.getAmount().toString());
        refundReqMessage.setAmount(amount);
        refundReqMessage.setCurrency(citicConfig.get("CITIC.EXPAY.CURRENCY"));
        String messageId = UUID.randomUUID().toString();
        expayMessage.setId(messageId.replaceAll("-", ""));
        expayMessage.setSysname(citicConfig.get("CITIC.EXPAY.SYSNAME"));
        expayMessage.setRefundReqMessage(refundReqMessage);
        reqMessage.setExpayMessage(expayMessage);
        return reqMessage;
        
    }

    /**
     * 
     * 功能描述：构建单笔查询报文
     *
     * @param citicExpay
     * @return
     * 
     * @author 宣广海
     *
     * @since 2016年6月27日
     *
     * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
     */
    public CiticExpayReqMessage buildExpayQueryReqMessage(CiticExpay citicExpay) {
        CiticExpayReqMessage reqMessage = new CiticExpayReqMessage();
        CiticExpayMessage expayMessage = new CiticExpayMessage();
        CiticExpayQueryReqMessage queryReqMessage = new CiticExpayQueryReqMessage();
        CpsGenMainOrder mainOrder = mainOrderQuery.get(citicExpay.getOrderId());
        queryReqMessage.setId("SOQReq");
        queryReqMessage.setStdprocode("SOQReq");
        queryReqMessage.setCertId(citicConfig.get("CITIC.EXPAY.CERTID"));
        queryReqMessage.setVersion(citicConfig.get("CITIC.EXPAY.VERSION"));
        queryReqMessage.setInstId(citicExpay.getMerID());
        //交易日期
        queryReqMessage.setDate(DateUtils.format(new Date(), DATE_FORMAT));
        // 要查询的订单日期，YYYYMMDD（需找银行确认是否精确到秒）
        queryReqMessage.setOrderDate(DateUtils.format(mainOrder.getCreatedTs(), DATE_FORMAT));
        // 交易流水号
        queryReqMessage.setSerialNo("SOQReq-"+citicExpay.getOrderId());
        //原订单号
        queryReqMessage.setOrgSerialNo(citicExpay.getBankOrderId());
        String messageId = UUID.randomUUID().toString();
        expayMessage.setId(messageId.replaceAll("-", ""));
        expayMessage.setSysname(citicConfig.get("CITIC.EXPAY.SYSNAME"));
        expayMessage.setQueryReqMessage(queryReqMessage);
        reqMessage.setExpayMessage(expayMessage);
        return reqMessage;
    }

    /**
     * 
     * 功能描述：构建鉴权请求报文
     *
     * @param citicExpay
     * @return
     * 
     * @author 宣广海
     *
     * @since 2016年6月29日
     *
     * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
     */
    public CiticExpayReqMessage buildExpayCerReqMessage(CiticExpay citicExpay) {
        CiticExpayReqMessage reqMessage = new CiticExpayReqMessage();
        CiticExpayMessage expayMessage = new CiticExpayMessage();
        CiticExpayCerReqMessage cerReqMessage = new CiticExpayCerReqMessage();
        cerReqMessage.setId("FPAReq");
        cerReqMessage.setCertId(citicConfig.get("CITIC.EXPAY.CERTID"));
        cerReqMessage.setVersion(citicConfig.get("CITIC.EXPAY.VERSION"));
        cerReqMessage.setInstId(citicExpay.getMerID());
        cerReqMessage.setStdprocode("FPAReq");
        cerReqMessage.setSerialNo("FPAReq-"+citicExpay.getOrderId());
        cerReqMessage.setName(citicExpay.getCardHolder());
        cerReqMessage.setDate(DateUtils.format(new Date(), DATE_FORMAT));
        cerReqMessage.setCertType("1");// 现在只支持身份证
        cerReqMessage.setCertNo(citicExpay.getIdentityCode());
        if (((BisBankBusinessProd._15.value).equals(citicExpay.getBankBusProd().value))
                || ((BisBankBusinessProd._20.value).equals(citicExpay.getBankBusProd().value))) {
            cerReqMessage.setCardType("D");// 借机卡
        }
        cerReqMessage.setCardNo(citicExpay.getCardNo());
        cerReqMessage.setMobilePhone(citicExpay.getMediaId());
        String messageId = UUID.randomUUID().toString();
        expayMessage.setId(messageId.replaceAll("-", ""));
        expayMessage.setSysname(citicConfig.get("CITIC.EXPAY.SYSNAME"));
        expayMessage.setCerReqMessage(cerReqMessage);
        reqMessage.setExpayMessage(expayMessage);
        return reqMessage;
    }

    /**
     * 
     * 功能描述：构建中信银行签约请求报文
     *
     * @param citicExpay
     * @return
     * 
     * @author 宣广海
     *
     * @since 2016年7月1日
     *
     * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
     */
    public CiticExpayReqMessage buildExpaySignReqMessage(CiticExpay citicExpay) {
        CiticExpayReqMessage reqMessage = new CiticExpayReqMessage();
        CiticExpayMessage expayMessage = new CiticExpayMessage();
        CiticExpaySignReqMessage sighReqMessage = new CiticExpaySignReqMessage();
        sighReqMessage.setId("SReq");
        sighReqMessage.setCertId(citicConfig.get("CITIC.EXPAY.CERTID"));
        sighReqMessage.setVersion(citicConfig.get("CITIC.EXPAY.VERSION"));
        sighReqMessage.setSerialNo("SReq-"+citicExpay.getOrderId());
        sighReqMessage.setStdprocode("SReq");
        sighReqMessage.setInstId(citicExpay.getMerID());
        sighReqMessage.setName(citicExpay.getCardHolder());
        sighReqMessage.setDate(DateUtils.format(new Date(), DATE_FORMAT));
        sighReqMessage.setCertType("1");// 现在只支持身份证
        sighReqMessage.setCertNo(citicExpay.getIdentityCode());
        if ((BisBankBusinessProd._15.value).equals(citicExpay.getBankBusProd().value)) {
            sighReqMessage.setCardType("D");// 借机卡
        }
        sighReqMessage.setCardNo(citicExpay.getCardNo());
        sighReqMessage.setMobilePhone(citicExpay.getMediaId());
        String messageId = UUID.randomUUID().toString();
        expayMessage.setId(messageId.replaceAll("-", ""));
        expayMessage.setSysname(citicConfig.get("CITIC.EXPAY.SYSNAME"));
        expayMessage.setSignReqMessage(sighReqMessage);
        reqMessage.setExpayMessage(expayMessage);
        return reqMessage;
    }

    /**
     * 
     * 功能描述：对象转化XML方法
     *
     * @param obj
     * @return
     * 
     * @author 宣广海
     *
     * @since 2016年6月20日
     *
     * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
     */
    public static <T> String toXML(T obj) {
        XStream xstream = new XStream();
        StringBuffer returnStr = new StringBuffer();
        String headStr = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
        xstream.autodetectAnnotations(true);
        xstream.aliasSystemAttribute(null, "class");
        String xmlStr = xstream.toXML(obj);
        returnStr.append(headStr);
        returnStr.append("\r\n");
        returnStr.append(xmlStr);
        return returnStr.toString();
    }

    /**
     * 
     * 功能描述：创建签约信息
     *
     * @param message
     * 
     * @author 宣广海
     *
     * @since 2016年9月6日
     *
     * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
     */
    public void createContract(ExPayBaseMessage message) {
        BisBankContractInfo bisBankContractInfo = new BisBankContractInfo();
        bisBankContractInfo.setBankCode(message.getBank());
        bisBankContractInfo.setBankBizProdCode(message.getBankBusProd().value);
        bisBankContractInfo.setIntrfaceChannelCode(message.getBankIntrChann().value);
        bisBankContractInfo.setCardNo(message.getCardNo());
        bisBankContractInfo.setContractState(BankContractConstants.CONTRACT_SUCCESS);
        bisBankContractInfo.setContractNumber(message.getAgrmtNo());
        bankContractInfoDAO.insertBisBankContractInfo(bisBankContractInfo);

    }

    /**
     * 根据卡号修改签约状态
     * 
     * @param message
     * @param state
     */
    public void updateContractByCardNo(ExPayBaseMessage message, String state) {
        BisBankContractInfo bisBankContractInfo = new BisBankContractInfo();
        bisBankContractInfo.setBankCode(message.getBank());
        bisBankContractInfo.setBankBizProdCode(message.getBankBusProd().value);
        bisBankContractInfo.setIntrfaceChannelCode(message.getBankIntrChann().value);
        bisBankContractInfo.setCardNo(message.getCardNo());
        bisBankContractInfo.setContractState(state);
        bankContractInfoDAO.updateContractStateByCardNo(bisBankContractInfo);
    }

    /**
     * 
     * 功能描述：检查是否已签约
     *
     * @param message
     * @return false:该卡未签约或签约作废 true：该卡已签约成功
     * 
     * @author 宣广海
     *
     * @since 2016年9月6日
     *
     * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
     */
    public BisBankContractInfo checkContract(ExPayBaseMessage message) {
        BisBankContractInfo bisBankContractInfo = new BisBankContractInfo();
        bisBankContractInfo.setBankCode(message.getBank());
        bisBankContractInfo.setBankBizProdCode(message.getBankBusProd().value);
        bisBankContractInfo.setIntrfaceChannelCode(message.getBankIntrChann().value);
        bisBankContractInfo.setCardNo(message.getCardNo());
        bisBankContractInfo = bankContractInfoDAO.getContractInfo(bisBankContractInfo);
        return bisBankContractInfo;
    }

    /**
     * 修改签约信息的日期，签约协议号（类似于重新签约）
     * 
     * @param message
     */
    public void againNewContract(ExPayBaseMessage message) {
        BisBankContractInfo bisBankContractInfo = new BisBankContractInfo();
        bisBankContractInfo.setBankCode(message.getBank());
        bisBankContractInfo.setBankBizProdCode(message.getBankBusProd().value);
        bisBankContractInfo.setIntrfaceChannelCode(message.getBankIntrChann().value);
        bisBankContractInfo.setCardNo(message.getCardNo());
        bisBankContractInfo.setContractState(BankContractConstants.CONTRACT_SUCCESS);
        bisBankContractInfo.setContractNumber(message.getAgrmtNo());
        bankContractInfoDAO.updateBisBankContractInfo(bisBankContractInfo);
    }
    
    /** 
     * 根据卡号，接口通道获取签约协议号
     * @param message
     * @return 
     * @author w_jiqing 
     */
    public BisBankContractInfo getSignNo(ExPayBaseMessage message){
        BisBankContractInfo bisBankContractInfo = new BisBankContractInfo();
        bisBankContractInfo.setBankCode(message.getBank());
        bisBankContractInfo.setIntrfaceChannelCode(message.getBankIntrChann().value);
        bisBankContractInfo.setCardNo(message.getCardNo());
        bisBankContractInfo = bankContractInfoDAO.getSignNoByCard(bisBankContractInfo);
        return bisBankContractInfo;
    }

}
